//
//  XKPagingView.m
//  BaiYing_Thinker
//
//  Created by 鹏 朱 on 15/10/29.
//  Copyright (c) 2015年 XKJH. All rights reserved.
//

#import "XKPagingView.h"
#import "ChatViewController.h"

@interface XKPagingView () <UIScrollViewDelegate>

- (void)configurePages;
- (void)configurePage:(UIView *)page forIndex:(NSInteger)index;

- (CGRect)frameForScrollView;
- (CGRect)frameForPageAtIndex:(NSUInteger)index;

- (void)recyclePage:(UIView *)page;

- (void)knownToBeMoving;
- (void)knownToBeIdle;

@end

@implementation XKPagingView

#pragma mark -
#pragma mark init/dealloc

- (void)commonInit {
    
    _visiblePages = [[NSMutableSet alloc] init];
    _recycledPages = [[NSMutableSet alloc] init];
    _currentPageIndex = 0;
    _gapBetweenPages = 0.0;
    _pagesToPreload = 1;
    _recyclingEnabled = YES;
    _firstLoadedPageIndex = _lastLoadedPageIndex = -1;

    self.clipsToBounds = YES;
    _scrollView = [[UIScrollView alloc] initWithFrame:[self frameForScrollView]];
    _scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    _scrollView.pagingEnabled = YES;
    _scrollView.backgroundColor = [UIColor blackColor];
    _scrollView.showsVerticalScrollIndicator = NO;
    _scrollView.showsHorizontalScrollIndicator = NO;
    _scrollView.bounces = YES;
    _scrollView.delegate = self;
    _scrollView.backgroundColor = [UIColor lightGrayColor];
    [self addSubview:_scrollView];
}

- (id)initWithCoder:(NSCoder *)aDecoder {
    if ((self = [super initWithCoder:aDecoder])) {
        _direction = ATPagingViewHorizontal;
        
        [self commonInit];
    }
    return self;
}

- (id)initWithFrame:(CGRect)frame {
    if ((self = [super initWithFrame:frame])) {
        _direction = ATPagingViewHorizontal;
        
        [self commonInit];
    }
    return self;
}

- (id)initVerticalWithFrame:(CGRect)frame {
    if ((self = [super initWithFrame:frame])) {
        _direction = ATPagingViewVertical;
        
        [self commonInit];
    }
    return self;
}

- (void)dealloc {

}


#pragma mark Properties

- (void)setDirection:(ATPagingViewDirection)direction {
    _direction = direction;
    [self setNeedsLayout];
}

- (void)setGapBetweenPages:(CGFloat)value {
    _gapBetweenPages = value;
    
    _scrollView.frame = [self frameForScrollView];
    
    [self setNeedsLayout];
}

- (void)setPagesToPreload:(NSInteger)value {
    _pagesToPreload = value;
    [self configurePages];
}


#pragma mark -
#pragma mark Data

- (void)reloadData {
    _pageCount = [_delegate numberOfPagesInPagingView:self];

    // recycle all pages
    for (UIView *view in _visiblePages) {
        [self recyclePage:view];
    }
    [_visiblePages removeAllObjects];

    [self configurePages];
}

- (void)reloadDataAtIndex:(NSInteger)index {

    UIView *page = [_delegate viewForPageInPagingView:self atIndex:index];
    [self configurePage:page forIndex:index];

}

#pragma mark -
#pragma mark Page Views

- (UIView *)viewForPageAtIndex:(NSUInteger)index {
    
    for (UIView *page in _visiblePages)
        if (page.tag == index)
            return page;
    return nil;
    
}

- (void)configurePages {
    if(_direction==ATPagingViewVertical){
        if (_scrollView.frame.size.height == 0)
            return;
    }else{
        if (_scrollView.frame.size.width == 0)
            return;
    }
    if (_rotationInProgress)
        return;

    BOOL quickMode = (_scrollViewIsMoving && _pagesToPreload > 0);

    CGSize contentSize = CGSizeZero;
    if(_direction==ATPagingViewVertical){
        contentSize = CGSizeMake(_scrollView.frame.size.width, _scrollView.frame.size.height * _pageCount);
        if(_pageCount==1){
            contentSize = CGSizeMake(_scrollView.frame.size.width, _scrollView.frame.size.height * _pageCount+10);
        }
    }else{
        contentSize = CGSizeMake(_scrollView.frame.size.width * _pageCount, _scrollView.frame.size.height);
    }
    
    if (!CGSizeEqualToSize(_scrollView.contentSize, contentSize)) {
        
#ifdef DEBUG
        NSLog(@"configurePages: _scrollView.frame == %@, setting _scrollView.contentSize = %@",
              NSStringFromCGRect(_scrollView.frame), NSStringFromCGSize(contentSize));
#endif
        _scrollView.contentSize = contentSize;
        
        if(_direction==ATPagingViewVertical){
            _scrollView.contentOffset = CGPointMake(0, _scrollView.frame.size.height * _currentPageIndex);
        }else{
            _scrollView.contentOffset = CGPointMake(_scrollView.frame.size.width * _currentPageIndex, 0);
        }
    } else {
#ifdef DEBUG
        NSLog(@"configurePages: _scrollView.frame == %@", NSStringFromCGRect(_scrollView.frame));
#endif
    }

    CGRect visibleBounds = _scrollView.bounds;
    NSInteger newPageIndex;
    if(_direction==ATPagingViewVertical){
        newPageIndex = MIN(MAX(floorf(CGRectGetMidY(visibleBounds) / CGRectGetHeight(visibleBounds)), 0), _pageCount - 1);
    }else{
        newPageIndex = MIN(MAX(floorf(CGRectGetMidX(visibleBounds) / CGRectGetWidth(visibleBounds)), 0), _pageCount - 1);
    }
    
#ifdef DEBUG
    NSLog(@"newPageIndex == %ld", newPageIndex);
#endif

    NSInteger firstVisiblePage = self.firstVisiblePageIndex;
    NSInteger lastVisiblePage  = self.lastVisiblePageIndex;
    NSInteger firstPage = MAX(0, MIN(firstVisiblePage, newPageIndex - _pagesToPreload));
    NSInteger lastPage  = MIN(_pageCount-1, MAX(lastVisiblePage,  newPageIndex + _pagesToPreload));

    NSMutableSet *pagesToRemove = [NSMutableSet set];
    for (UIView *page in _visiblePages) {
        if (page.tag < firstPage || page.tag > lastPage) {
            [self recyclePage:page];
            [pagesToRemove addObject:page];
        }
    }
    [_visiblePages minusSet:pagesToRemove];

    for (NSInteger index = firstPage; index <= lastPage; index++) {
        
        if (_direction == ATPagingViewHorizontal) {
            
            if (quickMode && (index < firstVisiblePage || index > lastVisiblePage))
                continue;

            NSMutableArray *list = [_delegate tableViewDataSource:self atIndex:index];
            
            ChatViewController* iv =(ChatViewController*)[self dequeueReusablePage];
            if (!iv) {
                iv =[[ChatViewController alloc] initWithFrame:self.frame dataSource:list previousDataList:nil nextDataList:nil];
                
                iv.scrollEnabled = YES;
                iv.scrollsToTop = YES;
                iv.showsVerticalScrollIndicator = YES;
            } else {
                iv.dataListOne = list;
                [iv reloadData];
            }
            
            [self configurePage:iv forIndex:index];
            [_scrollView addSubview:iv];
            [_visiblePages addObject:iv];
            
        } else {
            
            if ([self viewForPageAtIndex:index] == nil) {
                
                UIView *page = [_delegate viewForPageInPagingView:self atIndex:index];
                
                [self configurePage:page forIndex:index];
                [_scrollView addSubview:page];
                [_visiblePages addObject:page];
            }
        }
    }

    BOOL loadedPagesChanged;
    if (quickMode) {

        loadedPagesChanged = NO;
        
    } else {
        
        loadedPagesChanged = (_firstLoadedPageIndex != firstPage || _lastLoadedPageIndex != lastPage);
        if (loadedPagesChanged) {
            _firstLoadedPageIndex = firstPage;
            _lastLoadedPageIndex  = lastPage;
            NSLog(@"loadedPagesChanged: first == %ld, last == %ld", _firstLoadedPageIndex, _lastLoadedPageIndex);
        }
    }

    BOOL pageIndexChanged = (newPageIndex != _currentPageIndex);
    if (pageIndexChanged) {
        _previousPageIndex = _currentPageIndex;
        _currentPageIndex = newPageIndex;
        if ([_delegate respondsToSelector:@selector(currentPageDidChangeInPagingView:)])
            [_delegate currentPageDidChangeInPagingView:self];
        NSLog(@"_currentPageIndex == %ld", _currentPageIndex);
    }

    if (loadedPagesChanged || pageIndexChanged) {
        if ([_delegate respondsToSelector:@selector(pagesDidChangeInPagingView:)]) {
            NSLog(@"pagesDidChangeInPagingView");
            [_delegate pagesDidChangeInPagingView:self];
        }
    }
}

- (void)configurePage:(UIView *)page forIndex:(NSInteger)index {
    page.tag = index;
    page.frame = [self frameForPageAtIndex:index];
    [page setNeedsDisplay];
}


#pragma mark -
#pragma mark Rotation

- (void)willAnimateRotation {
    _rotationInProgress = YES;

    NSMutableSet *pagesToRemove = [NSMutableSet set];
    for (UIView *view in _visiblePages)
        if (view.tag != _currentPageIndex) {
            [self recyclePage:view];
            [pagesToRemove addObject:view];
        }
    [_visiblePages minusSet:pagesToRemove];

    CGSize pageSize = _scrollView.frame.size;
    
    if(_direction==ATPagingViewVertical){
        [self viewForPageAtIndex:_currentPageIndex].frame = CGRectMake(0, _scrollView.contentOffset.y + _gapBetweenPages/2, 
                                                                       pageSize.width, pageSize.height - _gapBetweenPages);
    }else{
        [self viewForPageAtIndex:_currentPageIndex].frame = CGRectMake(_scrollView.contentOffset.x + _gapBetweenPages/2, 0, pageSize.width - _gapBetweenPages, pageSize.height);
    }
}

- (void)didRotate {

    for (UIView *view in _visiblePages)
        [self configurePage:view forIndex:view.tag];
    
    if(_direction==ATPagingViewVertical){
        _scrollView.contentOffset = CGPointMake(0, _currentPageIndex * _scrollView.frame.size.height);
    }else{
        _scrollView.contentOffset = CGPointMake(_currentPageIndex * _scrollView.frame.size.width, 0);
    }
    _rotationInProgress = NO;

    [self configurePages];
}

#pragma mark -
#pragma mark Page navigation

- (void)setCurrentPageIndex:(NSInteger)newPageIndex {
    
#ifdef DEBUG
    NSLog(@"setCurrentPageIndex(%ld): _scrollView.frame == %@", newPageIndex, NSStringFromCGRect(_scrollView.frame));
#endif
    
    if (newPageIndex > _pageCount - 1) {
        newPageIndex = _pageCount - 1;
    } else if(newPageIndex < 0) {
        newPageIndex = 0;
    }
    
    if(_direction==ATPagingViewVertical){
        
        if (_scrollView.frame.size.height > 0 && fabs(_scrollView.frame.origin.y - (-_gapBetweenPages/2)) < 1e-6) {
            
            if (_openAnimator) {
                [_scrollView setContentOffset:CGPointMake(0, _scrollView.frame.size.height * newPageIndex) animated:1];
            } else {
                _scrollView.contentOffset = CGPointMake(0, _scrollView.frame.size.height * newPageIndex);
            }
            
        } else {
            _currentPageIndex = newPageIndex;
        }
    }else{
        if (_scrollView.frame.size.width > 0 && fabs(_scrollView.frame.origin.x - (-_gapBetweenPages/2)) < 1e-6) {
            _scrollView.contentOffset = CGPointMake(_scrollView.frame.size.width * newPageIndex, 0);

            
        } else {
            _currentPageIndex = newPageIndex;
        }
    }
}

- (void)setCurrentPageIndex:(NSInteger)newPageIndex openAnimator:(BOOL)openAnimator {
    self.openAnimator = openAnimator;
    [self setCurrentPageIndex:newPageIndex];
}


#pragma mark -
#pragma mark Layouting

- (void)layoutSubviews {
    if (_rotationInProgress)
        return;

    CGRect oldFrame = _scrollView.frame;
    CGRect newFrame = [self frameForScrollView];
    if (!CGRectEqualToRect(oldFrame, newFrame)) {
        _scrollView.frame = newFrame;
    }

    if(_direction==ATPagingViewVertical){
        
        if (oldFrame.size.height != 0 && _scrollView.frame.size.height != oldFrame.size.height) {
            
        } else if (oldFrame.size.width != _scrollView.frame.size.width) {
            
            [self configurePages];
            
        }
    }else{
        if (oldFrame.size.width != 0 && _scrollView.frame.size.width != oldFrame.size.width) {
            
        } else if (oldFrame.size.height != _scrollView.frame.size.height) {
            
            [self configurePages];
            
        }
    }
}

- (NSInteger)firstVisiblePageIndex {
    CGRect visibleBounds = _scrollView.bounds;
    
    if(_direction==ATPagingViewVertical){
        return MAX(floorf(CGRectGetMinY(visibleBounds) / CGRectGetHeight(visibleBounds)), 0);
    }
    
    return MAX(floorf(CGRectGetMinX(visibleBounds) / CGRectGetWidth(visibleBounds)), 0);
}

- (NSInteger)lastVisiblePageIndex {
    CGRect visibleBounds = _scrollView.bounds;
    
    if(_direction==ATPagingViewVertical){
        return MIN(floorf((CGRectGetMaxY(visibleBounds)-1) / CGRectGetHeight(visibleBounds)), _pageCount - 1);
    }
    
    return MIN(floorf((CGRectGetMaxX(visibleBounds)-1) / CGRectGetWidth(visibleBounds)), _pageCount - 1);
}

- (NSInteger)firstLoadedPageIndex {
    return _firstLoadedPageIndex;
}

- (NSInteger)lastLoadedPageIndex {
    return _lastLoadedPageIndex;
}

- (CGRect)frameForScrollView {
    CGSize size = self.bounds.size;
    
    if(_direction==ATPagingViewVertical){
        return CGRectMake(0, -_gapBetweenPages/2, size.width, size.height + _gapBetweenPages);
    }
    
    return CGRectMake(-_gapBetweenPages/2, 0, size.width + _gapBetweenPages, size.height);
}

- (CGRect)frameForPageAtIndex:(NSUInteger)index {
    CGSize pageSize = self.bounds.size;
    CGFloat pageWidthWithGap = _scrollView.frame.size.width;
    
    if(_direction==ATPagingViewVertical){
        CGFloat pageHeightWithGap = _scrollView.frame.size.height;
        return CGRectMake(0, pageHeightWithGap * index + _gapBetweenPages/2, 
                          pageSize.width, pageSize.height);
    }
    
    return CGRectMake(pageWidthWithGap * index + _gapBetweenPages/2,
                      0, pageSize.width, pageSize.height);
}


#pragma mark -
#pragma mark Recycling

- (void)recyclePage:(UIView *)page {
    if ([page respondsToSelector:@selector(prepareForReuse)]) {
        [(id)page prepareForReuse];
    }
    if (_recyclingEnabled) {
        [_recycledPages addObject:page];
    } else {
        NSLog(@"Releasing page %ld because recycling is disabled", page.tag);
    }
    [page removeFromSuperview];
}

- (UIView *)dequeueReusablePage {
    UIView *result = [_recycledPages anyObject];
    if (result) {
        [_recycledPages removeObject:result];
    }
    return result;
}


#pragma mark -
#pragma mark UIScrollViewDelegate methods
//
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if (_rotationInProgress)
        return;
    [self configurePages];
}

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
    [self knownToBeMoving];
}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
    if (!decelerate) {
        [self knownToBeIdle];
    }
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    [self knownToBeIdle];
}


#pragma mark -
#pragma mark Busy/Idle tracking

- (void)knownToBeMoving {
    if (!_scrollViewIsMoving) {
        _scrollViewIsMoving = YES;
        if ([_delegate respondsToSelector:@selector(pagingViewWillBeginMoving:)]) {
            [_delegate pagingViewWillBeginMoving:self];
        }
    }
}

- (void)knownToBeIdle {
    if (_scrollViewIsMoving) {
        _scrollViewIsMoving = NO;

        if (_pagesToPreload > 0) {

            [self configurePages];
            
        }

        if ([_delegate respondsToSelector:@selector(pagingViewDidEndMoving:)]) {
            [_delegate pagingViewDidEndMoving:self];
        }
    }
}

@end

#pragma mark -

@implementation ATPagingViewController

@synthesize pagingView=_pagingView;


#pragma mark -
#pragma mark init/dealloc

- (void)dealloc {

}


#pragma mark -
#pragma mark View Loading

- (void)loadView {
    self.view = self.pagingView = [[XKPagingView alloc] init];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    if (self.pagingView.delegate == nil)
        self.pagingView.delegate = self;
}


#pragma mark Lifecycle

- (void)viewWillAppear:(BOOL)animated {
    if (self.pagingView.pageCount == 0)
        [self.pagingView reloadData];
}


#pragma mark -
#pragma mark Rotation


- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
}

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
    [self.pagingView willAnimateRotation];
}

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
    [self.pagingView didRotate];
}


#pragma mark -
#pragma mark ATPagingViewDelegate methods

- (NSInteger)numberOfPagesInPagingView:(XKPagingView *)pagingView {
    return 0;
}

- (UIView *)viewForPageInPagingView:(XKPagingView *)pagingView atIndex:(NSInteger)index {
    return nil;
}

@end
